#include "bass_audio.h"
#include "audio_set.h"
#include "script/scripthelper.h"

#ifndef _PLATFORM_IOS_SIMULATOR // doesn't support properly yet
#include "bass/bass.h"
#endif

#include "vfs/vfs.h"
#include "script/scripthelper.h"

#include "util/log.h"				// log



#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    


#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#endif


using namespace audio;
using namespace script;

BassAudio&	BassAudio::Instance()
{
	static BassAudio Inst;
	return Inst;
}


void		BassAudio::Init(const std::string& AudioSetFile)
{


	m_IsInit = false;
	if (!BASS_Init(1,44100,0,0,NULL))
	{
		_LOG(MSG_WARNING, "Unable to load BASS sound system!");
		return;
	}
	Audio::Init(AudioSetFile);

#ifdef _PLATFORM_IOS
    //OBEY TO MUTE-SWITCH
    BASS_SetConfig(BASS_CONFIG_IOS_MIXAUDIO, 5);
#endif

}

void		BassAudio::Shutdown()
{

	if (m_IsInit)
	{
		BASS_Free();
		m_IsInit = false;
	}

}
unsigned int	BassAudio::GetFileSize(AudioHandle	Handle) 
{

	Sample*	pSample = m_Samples.GetElement(Handle);
	if (pSample && pSample->pData)
	{
		BASS_SAMPLE	SampleData;
		BASS_SampleGetInfo((HSAMPLE)pSample->pData, &SampleData);
		return SampleData.length;
	}

	return 0;
}

AudioHandle	BassAudio::PlaySFX(AudioFile	ID , float AudioBias)
{

    bool b;
	if (!m_IsInit) return 0;
	if (m_SFXVolume <= 0) return 0;

	Sample*	pSample = m_Samples.GetElement(ID);
	if (pSample && pSample->pData)
	{
		HCHANNEL Channel = BASS_SampleGetChannel((HSAMPLE)pSample->pData, false);
		if (Channel)
		{

            float v =  (float)(m_SFXVolume*m_AudioBias*AudioBias)/100.0f;
			b = BASS_ChannelSetAttribute(Channel,
                                     BASS_ATTRIB_VOL,
                                     v);


			BASS_ChannelPlay(Channel, true);
		}
		return Channel;
	}

	return 0;
}


AudioFile	BassAudio::LoadSoundFromMemory(vfs::LoadedBlock& Data, bool Repeat)
{

	unsigned int Flags = 0;
	if (Repeat) Flags |= BASS_SAMPLE_LOOP;
	HSAMPLE BasSample = BASS_SampleLoad(
		true,	// load from memory
		Data.DataArray,		// data to load
		0,					// offset in file, not used
		Data.Size,			// size of data
		10,					// max 10x playback
		Flags);					// flags
	if (!BasSample) 
		return 0;

	Sample*	pSample = new Sample;
	pSample->Size = Data.Size;
	pSample->File = Data.FileName;
	pSample->Handle = m_Samples.GetKey(Data.FileName);
	pSample->pData =  (intptr_t)BasSample;
	m_Samples.AddElement(Data.FileName, pSample);
	
    // CHIT: Can I release it now?
    Data.Reset();
    return pSample->Handle;

    return 0;
}

bool		BassAudio::IsPlaying(AudioHandle Handle)
{

	if (!m_IsInit) return false;
	if (Handle==0) return false;
	return BASS_ChannelIsActive(Handle) == BASS_ACTIVE_PLAYING;

    return false;
}

void		BassAudio::StopSound(AudioHandle Handle)
{

	if (!m_IsInit) return;

	BASS_ChannelStop(Handle);

}

void		BassAudio::StopMusic()
{

	if (!m_IsInit) return;

	if (m_CurrentMusic)
	{
		BASS_ChannelStop(m_CurrentMusic);
		m_CurrentMusic = 0;
	}

}


void		BassAudio::PauseAll()
{

	if (!m_IsInit) return;

	BASS_Pause();

}

void		BassAudio::RestartAll()
{

	if (!m_IsInit) return;

	BASS_Start();

}

void		BassAudio::SetMusicVolume(int	Volume)
{
    bool b;
	Audio::SetMusicVolume(Volume);
	if (m_CurrentMusic)
	{	
		b = BASS_ChannelSetAttribute(m_CurrentMusic,
                                 BASS_ATTRIB_VOL,
                                 (float)Volume / 100.0f
                                 );
	}

}

AudioHandle		BassAudio::PlayMusicH(AudioFile Handle, float AudioBias )
{

	if (!m_IsInit) return 0;

	m_MusicBias = AudioBias;
	// CHIT: MUTE / UNMUTE won't work if we don't play 
	//if (m_MusicVolume <= 5) return 0;	// really low
	if (m_CurrentMusic)
	{
		StopSound(m_CurrentMusic);
		BASS_MusicFree(m_CurrentMusic);
		m_CurrentMusic = 0;
	}

	m_MusicFile = 	"";

	Sample*	pSample = m_Samples.GetElement(Handle);
	if (pSample && pSample->pData)
	{
		HCHANNEL Channel = BASS_SampleGetChannel((HSAMPLE)pSample->pData, false);
		if (Channel)
		{
			m_CurrentMusic = Channel;
			BASS_ChannelPlay(Channel, true);
            SetMusicVolume(m_MusicVolume);
		}
		return Channel;
	}

	return 0;

}


AudioHandle	BassAudio::PlayMusic(const std::string& Name, float AudioBias, bool Repeat)
{

	if (!m_IsInit) return 0;

	// don't replay
	if (IsPlaying(m_CurrentMusic) && strcmpi(Name.c_str(), m_MusicFile.c_str()) == 0) return m_CurrentMusic;
	if (Name.empty()) return 0;

	std::string	Ext = vfs::VFS::GetExtension(Name);
	if (Ext == "ogg" || Ext == "mp3" || Ext == "wav") 
	{
		if (m_CurrentMusic)
		{
			StopSound(m_CurrentMusic);
			BASS_MusicFree(m_CurrentMusic);
			m_CurrentMusic = 0;
		}
		AudioHandle	Handle = LoadSound(Name, Repeat);
		if (Handle)
		{
			m_CurrentMusic = Handle;
			PlayMusicH(Handle, AudioBias);
		}
	} else
	{
		if (m_CurrentMusic)
		{
			StopSound(m_CurrentMusic);
			BASS_MusicFree(m_CurrentMusic);
			m_CurrentMusic = 0;
		}


		HMUSIC Music = NULL;		
		vfs::LoadedBlock	Data;
		if (vfs::VFS::Instance().GetFile(Name, Data))
		{
			unsigned long FLAGS = BASS_MUSIC_RAMPS|BASS_SAMPLE_LOOP| BASS_MUSIC_PRESCAN;
			if (!Repeat) FLAGS = BASS_MUSIC_RAMPS| BASS_MUSIC_PRESCAN;
			Music = BASS_MusicLoad(true,		// not from memory.. yet
					Data.DataArray,
					0,					// offset in file, not used
					Data.Size,			// size of data
					FLAGS,
					0);		

			if (Music)
			{
				_LOG(MSG_COMMENT, "Playing music " << Name);
				m_CurrentMusic = Music;
				SetMusicVolume(m_MusicVolume);
				DWORD handle = BASS_ChannelPlay(Music, true);
			}
		}
	}

	m_MusicFile = Name;
	return m_CurrentMusic;

    return 0;
}
